home *** CD-ROM | disk | FTP | other *** search
/ GFX Sensations 1 / Graphic Sensations - Volume 1.iso / tools / amiga / 3d_tools / irit40s.lha / Irit / irit / bool-hi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-30  |  20.8 KB  |  655 lines

  1. /*****************************************************************************
  2. *   "Irit" - the 3d (not only polygonal) solid modeller.             *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.2, Mar. 1990   *
  5. ******************************************************************************
  6. *   Module to handle the high level Boolean operations. The other modules    *
  7. * should only call this module to perform Boolean operations. All the        *
  8. * operations are none-destructives, meaning the given data is not modified.  *
  9. *   Note all the polygons of the two given objects must be convex, and the   *
  10. * returned object will also have only convex polygons!                 *
  11. *****************************************************************************/
  12.  
  13. /* #define DEBUG2             If defined, defines some printing routines. */
  14.  
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #include <math.h>
  18. #include <string.h>
  19. #include <signal.h>
  20. #include "program.h"
  21. #include "allocate.h"
  22. #include "attribut.h"
  23. #include "booleang.h"
  24. #include "booleanl.h"
  25. #include "convex.h"
  26. #include "poly_cln.h"
  27. #include "ctrl-brk.h"
  28. #include "geomat3d.h"
  29. #include "objects.h"
  30. #include "windows.h"
  31.  
  32. int BooleanOutputInterCurve = FALSE;    /* Kind of output from Boolean oper. */
  33.  
  34. static jmp_buf LclLongJumpBuffer;         /* Used in fatal Boolean error. */
  35. static int FatalErrorType,             /* Type of fatal Boolean error. */
  36.        BooleanOperation;           /* One of BooleanOR, BooleanAND, etc. */
  37.  
  38. static IPObjectStruct *BooleanCombineThreeObjs(IPObjectStruct *PObj1,
  39.                            IPObjectStruct *PObj2,
  40.                            IPObjectStruct *PObj3);
  41. static IPObjectStruct *BooleanCoplanar(IPObjectStruct *PObj1,
  42.                        IPObjectStruct *PObj2, int BoolOper);
  43. static IPObjectStruct *VerifyBooleanInput(IPObjectStruct *PObj1,
  44.                       IPObjectStruct *PObj2, int Oper);
  45. static IPPolygonStruct *ComputeRotatedPolys(IPPolygonStruct *Pl, int CopyPl,
  46.                                  MatrixType RotMat);
  47.  
  48. static void BooleanFPE(int Type);
  49. static void SetBooleanOutputKind(void);
  50.  
  51. #ifdef DEBUG2
  52. static void PrintVrtxList(IPVertexStruct *V);
  53. #endif /* DEBUG2 */
  54.  
  55. /*****************************************************************************
  56. *   Verify input for Booleans. Ret. NULL if OK, otherwise an obj to return.  *
  57. *****************************************************************************/
  58. static IPObjectStruct *VerifyBooleanInput(IPObjectStruct *PObj1,
  59.                       IPObjectStruct *PObj2, int Oper)
  60. {
  61.     IPObjectStruct *PObj;
  62.     IPPolygonStruct *Pl;
  63.  
  64.     BooleanOperation = Oper;
  65.  
  66.     SetBooleanOutputKind();
  67.  
  68.     if (!IP_IS_POLY_OBJ(PObj1) || (PObj2 != NULL && !IP_IS_POLY_OBJ(PObj2)))
  69.     IritFatalError("Boolean: operation on non polygonal object(s).");
  70.  
  71.     signal(SIGFPE, BooleanFPE);         /* Will trap floating point errors. */
  72.  
  73.     switch (Oper) {
  74.     case BOOL_OPER_OR:
  75.         if (IP_IS_POLYLINE_OBJ(PObj1) && IP_IS_POLYLINE_OBJ(PObj2)) {
  76.         if (PObj1 -> U.Pl == NULL)
  77.             PObj = CopyObject(NULL, PObj2, FALSE);
  78.         else {
  79.             PObj = CopyObject(NULL, PObj1, FALSE);
  80.             Pl = IritPrsrGetLastPoly(PObj -> U.Pl);
  81.             Pl -> Pnext = CopyPolygonList(PObj2 -> U.Pl);
  82.         }
  83.             return PObj;
  84.         }
  85.     case BOOL_OPER_AND:
  86.     case BOOL_OPER_SUB:
  87.     case BOOL_OPER_CUT:
  88.     case BOOL_OPER_MERGE:
  89.     case BOOL_OPER_NEG:
  90.             if (IP_IS_POLYLINE_OBJ(PObj1) ||
  91.         (PObj2 != NULL && IP_IS_POLYLINE_OBJ(PObj2))) {
  92.                 WndwInputWindowPutStr(
  93.         "Boolean: illegal operation on mixed polygon/line geometric object(s).");
  94.         PObj = GenPolyObject("", NULL, NULL);
  95.         return PObj;
  96.             }
  97.  
  98.         if (Oper != BOOL_OPER_NEG) {
  99.             ConvexPolyObject(PObj1);/* Make sure all polygons are convex.*/
  100.             ConvexPolyObject(PObj2);
  101.         }
  102.  
  103.         return NULL;
  104.     default:
  105.             IritFatalError("Boolean: undefined Boolean operation.");
  106.             return NULL;                 /* Make warning silent. */
  107.     }
  108. }
  109.  
  110. /*****************************************************************************
  111. *   Perform a Boolean OR between two objects.                     *
  112. *****************************************************************************/
  113. IPObjectStruct *BooleanOR(IPObjectStruct *PObj1, IPObjectStruct *PObj2)
  114. {
  115.     IPObjectStruct *PObj;
  116.     IPPolygonStruct *Pl;
  117.  
  118.     if ((PObj = VerifyBooleanInput(PObj1, PObj2, BOOL_OPER_OR)) != NULL)
  119.     return PObj;
  120.     else {
  121.     if (setjmp(LclLongJumpBuffer) == 0) { /* Its the setjmp itself call! */
  122.         signal(SIGFPE, BooleanFPE);     /* Will trap floating point errors. */
  123.         if (BooleanOutputInterCurve)
  124.         PObj = BooleanLow1Out2(PObj1, PObj2);/* Ret intersection crv.*/
  125.         else
  126.         PObj = BooleanCombineThreeObjs(BooleanLow1Out2(PObj1, PObj2),
  127.                            BooleanLow1Out2(PObj2, PObj1),
  128.                            BooleanCoplanar(PObj1, PObj2,
  129.                                    BOOL_OPER_OR));
  130.  
  131.     }
  132.     else {
  133.         /* We gain control from fatal error long jump - usually we should*/
  134.         /* return empty object, but if error is no intersection between  */
  135.         /* the two objects, we assume they have no common volume and     */
  136.         /* return a new object consists of the concat. of all polygons!  */
  137.         if (FatalErrorType != FTL_BOOL_NO_INTER) {
  138.         PObj = GenPolyObject("", NULL, NULL);/* Return empty object. */
  139.         }
  140.         else {
  141.         if (PObj1 -> U.Pl == NULL)
  142.             PObj = CopyObject(NULL, PObj2, FALSE);
  143.         else {
  144.             PObj = CopyObject(NULL, PObj1, FALSE);/* Copy Obj1 polys.*/
  145.             Pl = PObj -> U.Pl;
  146.             while (Pl -> Pnext) Pl = Pl -> Pnext;
  147.             Pl -> Pnext = CopyPolygonList(PObj2 -> U.Pl);/*Obj2 poly.*/
  148.         }
  149.         }
  150.     }
  151.     }
  152.  
  153.     signal(SIGFPE, DefaultFPEHandler);                /* Default FPE trapping. */
  154.  
  155.     AttrSetObjectColor(PObj, BooleanOutputInterCurve ?
  156.                  GlblICrvColor :
  157.                  GlblBoolColor);   /* Default bool object color. */
  158.  
  159.     return PObj;
  160. }
  161.  
  162. /*****************************************************************************
  163. *   Perform a Boolean AND between two objects.                     *
  164. *****************************************************************************/
  165. IPObjectStruct *BooleanAND(IPObjectStruct *PObj1, IPObjectStruct *PObj2)
  166. {
  167.     IPObjectStruct *PObj;
  168.  
  169.     if ((PObj = VerifyBooleanInput(PObj1, PObj2, BOOL_OPER_AND)) != NULL)
  170.     return PObj;
  171.     else {
  172.     if (setjmp(LclLongJumpBuffer) == 0) { /* Its the setjmp itself call! */
  173.         signal(SIGFPE, BooleanFPE);     /* Will trap floating point errors. */
  174.         if (BooleanOutputInterCurve)
  175.         PObj = BooleanLow1In2(PObj1, PObj2);/* Ret intersection crv. */
  176.         else
  177.         PObj = BooleanCombineThreeObjs(BooleanLow1In2(PObj1, PObj2),
  178.                            BooleanLow1In2(PObj2, PObj1),
  179.                            BooleanCoplanar(PObj1, PObj2,
  180.                                    BOOL_OPER_AND));
  181.  
  182.     }
  183.     else {/* We gain control from fatal error long jump - ret empty obj. */
  184.         PObj = GenPolyObject("", NULL, NULL);
  185.     }
  186.     }
  187.  
  188.     signal(SIGFPE, DefaultFPEHandler);            /* Default FPE trapping. */
  189.  
  190.     AttrSetObjectColor(PObj, BooleanOutputInterCurve ?
  191.                  GlblICrvColor :
  192.                  GlblBoolColor);   /* Default bool object color. */
  193.  
  194.     return PObj;
  195. }
  196.  
  197. /*****************************************************************************
  198. *   Perform a Boolean SUBSTRACT between two objects (PObj1 - PObj2).         *
  199. *****************************************************************************/
  200. IPObjectStruct *BooleanSUB(IPObjectStruct *PObj1, IPObjectStruct *PObj2)
  201. {
  202.     IPObjectStruct *PObj, *PTemp, *PTempRev;
  203.  
  204.     if ((PObj = VerifyBooleanInput(PObj1, PObj2, BOOL_OPER_SUB)) != NULL)
  205.     return PObj;
  206.     else {
  207.     if (setjmp(LclLongJumpBuffer) == 0) { /* Its the setjmp itself call! */
  208.         signal(SIGFPE, BooleanFPE);     /* Will trap floating point errors. */
  209.         /* The 1 in 2 must be reversed (the inside/outside orientation): */
  210.         if (BooleanOutputInterCurve) {
  211.         PObj = BooleanLow1In2(PObj2, PObj1);/* Ret intersection crv. */
  212.         }
  213.         else {
  214.         PTemp = BooleanLow1In2(PObj2, PObj1);
  215.         PTempRev = BooleanNEG(PTemp);
  216.         IPFreeObject(PTemp);
  217.  
  218.         PObj = BooleanCombineThreeObjs(BooleanLow1Out2(PObj1, PObj2),
  219.                            PTempRev,
  220.                            BooleanCoplanar(PObj1, PObj2,
  221.                                    BOOL_OPER_SUB));
  222.         }
  223.     }
  224.     else {/* We gain control from fatal error long jump - ret empty obj. */
  225.         PObj = GenPolyObject("", NULL, NULL);
  226.     }
  227.     }
  228.  
  229.     signal(SIGFPE, DefaultFPEHandler);                /* Default FPE trapping. */
  230.  
  231.     AttrSetObjectColor(PObj, BooleanOutputInterCurve ?
  232.                  GlblICrvColor :
  233.                  GlblBoolColor);   /* Default bool object color. */
  234.  
  235.     return PObj;
  236. }
  237.  
  238. /*****************************************************************************
  239. *   Perform a Boolean CUT between two objects (PObj1 / PObj2).             *
  240. *****************************************************************************/
  241. IPObjectStruct *BooleanCUT(IPObjectStruct *PObj1, IPObjectStruct *PObj2)
  242. {
  243.     IPObjectStruct *PObj;
  244.  
  245.     if ((PObj = VerifyBooleanInput(PObj1, PObj2, BOOL_OPER_CUT)) != NULL)
  246.     return PObj;
  247.     else {
  248.     if (setjmp(LclLongJumpBuffer) == 0) { /* Its the setjmp itself call! */
  249.         signal(SIGFPE, BooleanFPE);     /* Will trap floating point errors. */
  250.         /* The 1 in 2 must be reversed (the inside/outside orientation): */
  251.         if (BooleanOutputInterCurve) {
  252.         PObj = BooleanLow1In2(PObj2, PObj1);/* Ret intersection crv. */
  253.         }
  254.         else {
  255.         PObj = BooleanLow1Out2(PObj1, PObj2);
  256.         }
  257.     }
  258.     else {/* We gain control from fatal error long jump - ret empty obj. */
  259.         PObj = GenPolyObject("", NULL, NULL);
  260.     }
  261.     }
  262.  
  263.     signal(SIGFPE, DefaultFPEHandler);                /* Default FPE trapping. */
  264.  
  265.     AttrSetObjectColor(PObj, BooleanOutputInterCurve ?
  266.                  GlblICrvColor :
  267.                  GlblBoolColor);   /* Default bool object color. */
  268.  
  269.     return PObj;
  270. }
  271.  
  272. /*****************************************************************************
  273. *   Perform a Boolean MERGE between two objects.                 *
  274. *****************************************************************************/
  275. IPObjectStruct *BooleanMERGE(IPObjectStruct *PObj1, IPObjectStruct *PObj2)
  276. {
  277.     IPObjectStruct *PObj;
  278.     IPPolygonStruct *Pl;
  279.  
  280.     if ((PObj = VerifyBooleanInput(PObj1, PObj2, BOOL_OPER_MERGE)) != NULL)
  281.     return PObj;
  282.     else {
  283.     if (PObj1 -> U.Pl == NULL)
  284.             PObj = CopyObject(NULL, PObj2, FALSE);
  285.         else {
  286.             PObj = CopyObject(NULL, PObj1, FALSE);       /* Copy Obj1 polys. */
  287.         Pl = PObj -> U.Pl;
  288.         while (Pl -> Pnext) Pl = Pl -> Pnext;
  289.         Pl -> Pnext = CopyPolygonList(PObj2 -> U.Pl);     /* Obj2 polys. */
  290.     }
  291.     }
  292.  
  293.     AttrSetObjectColor(PObj, GlblBoolColor);   /* Default bool object color. */
  294.  
  295.     return PObj;
  296. }
  297.  
  298. /*****************************************************************************
  299. *   Perform a Boolean NEGATION of given object PObj.                 *
  300. *  Negation is simply reversing the direction of the plane equation of each  *
  301. * polygon - the simplest Boolean operation...                     *
  302. *****************************************************************************/
  303. IPObjectStruct *BooleanNEG(IPObjectStruct *PObj)
  304. {
  305.     int i;
  306.     IPObjectStruct *PTemp;
  307.     IPPolygonStruct *Pl;
  308.     IPVertexStruct *V;
  309.  
  310.     if ((PTemp = VerifyBooleanInput(PObj, NULL, BOOL_OPER_NEG)) != NULL)
  311.     return PTemp;
  312.     else {
  313.     PTemp = CopyObject(NULL, PObj, FALSE); /* Make fresh copy of object. */
  314.  
  315.     /* Scans all polygons and reverse plane equation and their vetrex    */
  316.     /* list (cross prod. of consecutive edges must be in normal dir.).   */
  317.     Pl = PTemp -> U.Pl;
  318.     while (Pl != NULL) {
  319.         for (i = 0; i < 4; i++) Pl -> Plane[i] = (-Pl -> Plane[i]);
  320.         IP_RST_CONVEX_POLY(Pl);
  321.  
  322.         /* Invert vertices normals as well. */
  323.         V = Pl -> PVertex;
  324.         do {
  325.         PT_SCALE(V -> Normal, -1.0);
  326.         V = V -> Pnext;
  327.         }
  328.         while (V != NULL && V != Pl -> PVertex);
  329.  
  330.         Pl = Pl -> Pnext;
  331.     }
  332.     }
  333.  
  334.     signal(SIGFPE, DefaultFPEHandler);            /* Default FPE trapping. */
  335.  
  336.     AttrSetObjectColor(PTemp, BooleanOutputInterCurve ?
  337.                   GlblICrvColor :
  338.                   GlblBoolColor);  /* Default bool object color. */
  339.  
  340.     return PTemp;
  341. }
  342.  
  343. /*****************************************************************************
  344. *  Combining three geometric objects, by simply concat. their polygon lists: *
  345. *  Any object may be NULL in which only the other two are merged.         *
  346. *****************************************************************************/
  347. static IPObjectStruct *BooleanCombineThreeObjs(IPObjectStruct *PObj1,
  348.                            IPObjectStruct *PObj2,
  349.                            IPObjectStruct *PObj3)
  350. {
  351.     IPPolygonStruct *Pl;
  352.  
  353.     if (PObj1 == NULL) {
  354.     PObj1 = PObj2;
  355.     PObj2 = PObj3;
  356.     PObj3 = NULL;
  357.     }
  358.     if (PObj2 == NULL) {
  359.     PObj2 = PObj3;
  360.     PObj3 = NULL;
  361.     }
  362.  
  363.     if (PObj1 != NULL)
  364.     CleanUpPolygonList(&PObj1 -> U.Pl);
  365.     if (PObj2 != NULL)
  366.     CleanUpPolygonList(&PObj2 -> U.Pl);
  367.     if (PObj3 != NULL)
  368.     CleanUpPolygonList(&PObj3 -> U.Pl);
  369.  
  370.     if (PObj2 != NULL) {
  371.     /* Concat the polygons of PObj2 after the polygons of PObj1. */
  372.     Pl = PObj1 -> U.Pl;
  373.     while (Pl -> Pnext != NULL)
  374.         Pl = Pl -> Pnext;
  375.     Pl -> Pnext = PObj2 -> U.Pl;  /* Concat. the polygons into one list. */
  376.     PObj2 -> U.Pl = NULL;        /* And release the second object header. */
  377.     IPFreeObject(PObj2);
  378.  
  379.         if (PObj3 != NULL) {
  380.         /* Concat the polygons of PObj3 after the polygons of PObj1/2. */
  381.         while (Pl -> Pnext != NULL)
  382.         Pl = Pl -> Pnext;
  383.         Pl -> Pnext = PObj3 -> U.Pl;  /* Concat. polygons into one list. */
  384.         PObj3 -> U.Pl = NULL;   /* And release the second object header. */
  385.         IPFreeObject(PObj3);
  386.         }
  387.     }
  388.  
  389.     return PObj1;
  390. }
  391.  
  392. /*****************************************************************************
  393. *  If required (I.e. Object "COPLANAR" is set to TRUE) search all coplanar   *
  394. * polygons in PObj1/2 and invoke the necessary two dimenstional Boolean.     *
  395. *****************************************************************************/
  396. static IPObjectStruct *BooleanCoplanar(IPObjectStruct *PObj1,
  397.                        IPObjectStruct *PObj2, int BoolOper)
  398. {
  399.     int HandleCoplanar;
  400.     MatrixType RotMat;
  401.     IPObjectStruct *PObj,
  402.     *PCoplanar = GetObject("COPLANAR");
  403.     IPPolygonStruct *Pl, *PlTmp, *Pl1, *Pl2, *Pl1XY, *Pl2XY, *Pl1XYR, *Pl2XYR,
  404.     *PlOut = NULL;
  405.  
  406.     if (PCoplanar == NULL || !IP_IS_NUM_OBJ(PCoplanar)) {
  407.     WndwInputWindowPutStr("No numeric object name COPLANAR is defined");
  408.     HandleCoplanar = FALSE;
  409.     }
  410.     else
  411.     HandleCoplanar = (int) (PCoplanar -> U.R);
  412.  
  413.     if (!HandleCoplanar)
  414.     return NULL;
  415.  
  416.     for ( Pl1 = PObj1 -> U.Pl; Pl1 != NULL; Pl1 = Pl1 -> Pnext) {
  417.         for ( Pl2 = PObj2 -> U.Pl; Pl2 != NULL; Pl2 = Pl2 -> Pnext) {
  418.         RealType
  419.         *Plane1 = Pl1 -> Plane,
  420.         *Plane2 = Pl2 -> Plane;
  421.         int Shared = APX_EQ(Plane1[0], Plane2[0]) &&
  422.                  APX_EQ(Plane1[1], Plane2[1]) &&
  423.                  APX_EQ(Plane1[2], Plane2[2]) &&
  424.                  APX_EQ(Plane1[3], Plane2[3]),
  425.         AntiShared = APX_EQ(Plane1[0], -Plane2[0]) &&
  426.                  APX_EQ(Plane1[1], -Plane2[1]) &&
  427.                  APX_EQ(Plane1[2], -Plane2[2]) &&
  428.                  APX_EQ(Plane1[3], -Plane2[3]);
  429.  
  430.         if (!Shared && !AntiShared) {
  431.         /* The two polygons are not coplanar, do not intersect. */
  432.         continue;
  433.         }
  434.  
  435.         if (Shared) {
  436.         switch (BoolOper) {
  437.             case BOOL_OPER_AND:
  438.             case BOOL_OPER_OR:
  439.             case BOOL_OPER_SUB:
  440.             GenRotateMatrix(RotMat, Pl1 -> Plane);
  441.             Pl1XY = ComputeRotatedPolys(Pl1, TRUE, RotMat);
  442.             Pl2XY = ComputeRotatedPolys(Pl2, TRUE, RotMat);
  443.             /* Find the inverse matrix. */
  444.             if (!MatInverseMatrix(RotMat, RotMat))
  445.                 IritFatalError("BooleanCoplanar: Inverse matrix does not exists");
  446.  
  447.             if ((Pl = Boolean2D(Pl1XY, Pl2XY, BoolOper)) != NULL) {
  448.                 Pl = ComputeRotatedPolys(Pl, FALSE, RotMat);
  449.                 for (PlTmp = Pl;
  450.                  PlTmp -> Pnext != NULL;
  451.                  PlTmp = PlTmp -> Pnext);
  452.                 PlTmp -> Pnext = PlOut;
  453.                 PlOut = Pl;
  454.             }
  455.  
  456.             IPFreePolygonList(Pl1XY);
  457.             IPFreePolygonList(Pl2XY);
  458.             break;
  459.  
  460.             default:
  461.                 IritFatalError("BooleanCoplanar: Unsupported Boolean operation BooleanCoplanar");
  462.                 return NULL;
  463.         }
  464.         }
  465.         else if (AntiShared) {
  466.         switch (BoolOper) {
  467.             case BOOL_OPER_AND:
  468.             case BOOL_OPER_SUB:
  469.             WndwInputWindowPutStr("Antishared coplanar polygons are ignored.");
  470.             break;
  471.  
  472.             case BOOL_OPER_OR:
  473.             GenRotateMatrix(RotMat, Pl1 -> Plane);
  474.             Pl1XY = ComputeRotatedPolys(Pl1, TRUE, RotMat);
  475.             Pl1XYR = CopyPolygonList(Pl1XY);
  476.             IritPrsrReverseVrtxList(Pl1XYR);
  477.             Pl2XY = ComputeRotatedPolys(Pl2, TRUE, RotMat);
  478.             Pl2XYR = CopyPolygonList(Pl2XY);
  479.             IritPrsrReverseVrtxList(Pl2XYR);
  480.  
  481.             if (!MatInverseMatrix(RotMat, RotMat))
  482.                 IritFatalError("BooleanCoplanar: Inverse matrix does not exists");
  483.  
  484.             if ((Pl = Boolean2D(Pl1XY, Pl2XYR, BOOL_OPER_SUB)) != NULL) {
  485.                 Pl = ComputeRotatedPolys(Pl, FALSE, RotMat);
  486.                 for (PlTmp = Pl;
  487.                  PlTmp -> Pnext != NULL;
  488.                  PlTmp = PlTmp -> Pnext);
  489.                 PlTmp -> Pnext = PlOut;
  490.                 PlOut = Pl;
  491.             }
  492.             if ((Pl = Boolean2D(Pl2XY, Pl1XYR, BOOL_OPER_SUB)) != NULL) {
  493.                 Pl = ComputeRotatedPolys(Pl, FALSE, RotMat);
  494.                 for (PlTmp = Pl;
  495.                  PlTmp -> Pnext != NULL;
  496.                  PlTmp = PlTmp -> Pnext);
  497.                 PlTmp -> Pnext = PlOut;
  498.                 PlOut = Pl;
  499.             }
  500.  
  501.             IPFreePolygonList(Pl1XY);
  502.             IPFreePolygonList(Pl2XY);
  503.             IPFreePolygonList(Pl1XYR);
  504.             IPFreePolygonList(Pl2XYR);
  505.             break;
  506.  
  507.             default:
  508.                 IritFatalError("BooleanCoplanar: Unsupported Boolean operation BooleanCoplanar");
  509.                 return NULL;
  510.         }
  511.         }
  512.     }
  513.     }
  514.  
  515.     PObj = IPAllocObject("", IP_OBJ_POLY, NULL);
  516.     PObj -> U.Pl = PlOut;
  517.     return PObj;
  518. }
  519.  
  520. /*****************************************************************************
  521. *   Routine to optionally copy (if CpolyOnePl) a single polygon and rotate   *
  522. * according to the rotation matrix provided. If, however, CopyOnePl is False *
  523. * all polygons in list are converted.                         *
  524. *****************************************************************************/
  525. static IPPolygonStruct *ComputeRotatedPolys(IPPolygonStruct *Pl, int CopyOnePl,
  526.                                  MatrixType RotMat)
  527. {
  528.     IPVertexStruct *V, *VHead;
  529.     IPPolygonStruct *PlNext, *PlTemp,
  530.     *PlOut = NULL;
  531.  
  532.     while (Pl != NULL) {
  533.     PlNext = Pl -> Pnext;
  534.  
  535.     if (CopyOnePl) {
  536.         PlTemp = IPAllocPolygon(Pl -> Count, Pl -> Tags,
  537.                     CopyVertexList(Pl -> PVertex), NULL);
  538.         PLANE_COPY(PlTemp ->Plane, Pl -> Plane);
  539.         Pl = PlTemp;
  540.     }
  541.  
  542.     V = VHead = Pl -> PVertex;
  543.     do {                    /* Transform the polygon itself. */
  544.         PointType PTemp;
  545.  
  546.         PT_ADD(PTemp, V -> Coord, V -> Normal);
  547.  
  548.         MatMultVecby4by4(V -> Coord, V -> Coord, RotMat);
  549.  
  550.         MatMultVecby4by4(PTemp, PTemp, RotMat);   /* Update normal. */
  551.         PT_SUB(V -> Normal, PTemp, V -> Coord);
  552.         PT_NORMALIZE(V -> Normal);
  553.  
  554.         V = V -> Pnext;
  555.     }
  556.     while (V != NULL && V != VHead);
  557.  
  558.     Pl -> Pnext = PlOut;
  559.     PlOut = Pl;
  560.  
  561.     if (CopyOnePl)
  562.         break;
  563.     else
  564.         Pl = PlNext;
  565.     }
  566.  
  567.     return PlOut;
  568. }
  569.  
  570. /*****************************************************************************
  571. *   Routine that is called from the floating point package in case of fatal  *
  572. * floating point error. Print error message, and quit the Boolean module.    *
  573. *****************************************************************************/
  574. static void BooleanFPE(int Type)
  575. {
  576.     char Line[LINE_LEN];
  577.  
  578.     sprintf(Line, "Floating point error %d.", Type);
  579.     WndwInputWindowPutStr(Line);
  580.  
  581.     FatalErrorType = FTL_BOOL_FPE;
  582.  
  583.     longjmp(LclLongJumpBuffer, 1);
  584. }
  585.  
  586. /*****************************************************************************
  587. *   Routine to select the output kind needed. Output of a Boolean operator   *
  588. * can be the real Boolean result model, or the intersection curves only.     *
  589. *****************************************************************************/
  590. static void SetBooleanOutputKind(void)
  591. {
  592.     IPObjectStruct *PObj = GetObject("INTERCRV");
  593.  
  594.     if (PObj == NULL || !IP_IS_NUM_OBJ(PObj)) {
  595.     WndwInputWindowPutStr("No numeric object name INTERCRV is defined");
  596.     BooleanOutputInterCurve = FALSE;
  597.     }
  598.     else
  599.     BooleanOutputInterCurve = !APX_EQ(PObj -> U.R, 0.0);
  600. }
  601.  
  602. /*****************************************************************************
  603. *   Routine that is called by the bool-low module in fatal cases errors.     *
  604. * Will print error message and long jump using LclLongJumpBuffer.         *
  605. *****************************************************************************/
  606. void FatalBooleanError(int ErrorType)
  607. {
  608.     char s[LINE_LEN_LONG];
  609.  
  610.     FatalErrorType = ErrorType;
  611.  
  612.     switch (ErrorType) {
  613.     case FTL_BOOL_NO_INTER:
  614.         /* If operation is union (OR), then if no intersection we assume */
  615.         /* the objects have no common volume and simply combine them!    */
  616.         if (BooleanOperation != BOOL_OPER_OR) {
  617.         sprintf(s, "Boolean: %s",
  618.             "Objects do not intersect - Empty object result");
  619.         WndwInputWindowPutStr(s);
  620.         }
  621.         break;
  622.     default:
  623.         sprintf(s, "Boolean: Undefined Fatal Error (%d !?)", ErrorType);
  624.         WndwInputWindowPutStr(s);
  625.         break;
  626.     }
  627.  
  628.     longjmp(LclLongJumpBuffer, 1);
  629. }
  630.  
  631. #ifdef DEBUG2
  632.  
  633. /*****************************************************************************
  634. *   Print the content of the given polygon, to standard output.             *
  635. *****************************************************************************/
  636. static void PrintVrtxList(IPVertexStruct *V)
  637. {
  638.     IPVertexStruct
  639.     *VHead = V;
  640.  
  641.     do {
  642.     printf("[NORMAL %8lf %8lf %8lf] %12lf %12lf %12lf",
  643.            V -> Normal[0], V -> Normal[1], V -> Normal[2],
  644.            V -> Coord[0], V -> Coord[1], V -> Coord[2]);
  645.     if (IP_IS_INTERNAL_EDGE(V))
  646.         printf(" (Internal)\n");
  647.     else
  648.         printf("\n");
  649.     V = V -> Pnext;
  650.     }
  651.     while (V!= NULL && V != VHead);
  652. }
  653.  
  654. #endif /* DEBUG2 */
  655.